<?php
namespace App\Config;

use Phalcon\Config;
use Phalcon\Cache\Frontend\Data as FrontendData;
use Phalcon\Cache\Backend\Libmemcached as PhalconMemcached;
use Phalcon\Cache\Backend\Memcache as PhalconMemcache;
use Phalcon\Crypt;
use Phalcon\Di as DI;
use Phalcon\Db\Profiler;
use Phalcon\Db\Adapter\Pdo\Mysql as DbAdapter;
use Phalcon\Events\Manager as EventsManager;
use Phalcon\Http\Response;
use Phalcon\Http\Request;
use Phalcon\Http\Response\Cookies;
use Phalcon\Loader;
use Phalcon\Logger\Formatter\Line as LineFormatter;
use Phalcon\Logger\Adapter\File as LoggerAdapterFile;
use Phalcon\Mvc\Application;
use Phalcon\Mvc\Dispatcher;
use Phalcon\Mvc\View;
use Phalcon\Mvc\View\Simple as SimpleView;
use Phalcon\Mvc\View\Engine\Volt as VoltViewEngine;
use Phalcon\Mvc\Url as UrlResolver;
use Phalcon\Mvc\Model\Manager as ModelsManager;
use Phalcon\Mvc\Model\MetaData\Memory as MetaDataMemory;

class Bootstrap extends Application {
    /**
     * @var \Phalcon\Config
     */
    private $config;

    /**
     * @return \Phalcon\Config
     */
    private function config() {
        if(!is_object($this->config)) {
            $this->config = include APP_PATH . "Config/Config.php";
        }
        return $this->config;
    }

    protected function registerAutoloaders() {
        $loader = new Loader();

        $loader->registerNamespaces([
            'App\Config'      => APP_PATH . 'Config/',
            'App\Controllers' => APP_PATH . 'Controllers/',
            'App\Models'      => APP_PATH . 'Models/',
            'App\Library'     => APP_PATH . 'Library/',
            'App\Plugin'      => APP_PATH . 'Plugins/',
            'App\Vendor'      => APP_PATH . 'Vendor/'
        ]);

        $loader->registerDirs([
            'configDir'      => $this->config()->application->configDir,
            'controllersDir' => $this->config()->application->controllersDir,
            'modelsDir'      => $this->config()->application->modelsDir,
            'viewsDir'       => $this->config()->application->viewsDir,
            'libraryDir'     => $this->config()->application->libraryDir,
            'pluginsDir'     => $this->config()->application->pluginsDir,
            'vendorDir'      => $this->config()->application->vendorDir,
        ]);

        $loader->register();
    }

    protected function registerServices() {
        $di     = new DI();
        $config = $this->config();
        $di->set('router', function () {
            return include APP_PATH . 'Config/Routes.php';
        });
        $di->set('dispatcher', function () {
            $dispatcher = new Dispatcher();
            $dispatcher->setDefaultNamespace('App\Controllers\\');
            return $dispatcher;
        });
        $di->set('response', function () {
            return new Response();
        });
        $di->set('request', function () {
            return new Request();
        });
        $di->set('voltService', function ($view, $di) use ($config) {
            $volt = new VoltViewEngine($view, $di);
            $volt->setOptions([
                "compiledPath"      => $config->application->cacheDir,
                "compiledExtension" => ".cvolt"
            ]);
            return $volt;
        }, true);
        $di->set('view', function () use ($config) {
            $view = new View();
            $view->setViewsDir($config->application->viewsDir);
            $view->registerEngines([
                ".phtml" => 'Phalcon\Mvc\View\Engine\Php',
                ".volt"  => 'voltService'
            ]);
            $view->disableLevel([
                View::LEVEL_BEFORE_TEMPLATE => true,
                View::LEVEL_AFTER_TEMPLATE  => true,
                //View::LEVEL_LAYOUT => true,
                View::LEVEL_MAIN_LAYOUT     => true,
                View::LEVEL_ACTION_VIEW     => true,
            ]);
            return $view;
        });
        $di->set('simple_view', function () use ($config) {
            $view = new SimpleView();
            $view->setViewsDir($config->application->viewsDir);
            $view->registerEngines([
                ".phtml" => 'Phalcon\Mvc\View\Engine\Php',
                ".volt"  => 'voltService'
            ]);
            return $view;
        }, true);

        $di->set('profiler', function () {
            return new Profiler();
        }, true);
        $di->set('db', function () use ($config) {
            $db = new DbAdapter([
                "host"     => $config->database->host,
                "username" => $config->database->username,
                "password" => $config->database->password,
                "dbname"   => $config->database->dbname,
                'charset'  => 'utf8',
                "options"  => [
                    \PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
                    \PDO::ATTR_EMULATE_PREPARES   => false,
                    \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC
                ]
            ]);
            //测试环境建立一个事件监听
            if(defined('ENVIRONMENT') && ENVIRONMENT == 'development') {
                $eventsManager = new EventsManager();
                //$profiler      = $di->getShared('profiler');
                $profiler = new Profiler();
                $eventsManager->attach('db', function ($event, $connection) use ($profiler) {
                    if($event->getType() == 'beforeQuery') {
                        $profiler->startProfile($connection->getSQLStatement());
                    }
                    if($event->getType() == 'afterQuery') {
                        $profiler->stopProfile();
                    }
                });
                $db->setEventsManager($eventsManager);
            }
            return $db;
        });
        $di->set('globalConfig', function () use ($config) {
            return $config;
        }, true);
        $di->set('logger', function () use ($config) {
            $logger = new LoggerAdapterFile($config->application->logsDir . date('Ymd') . ".log");
            $logger->setFormatter(new LineFormatter('[%date%][%type%] [%message%]', 'Y-m-d H:i:s'));
            return $logger;
        }, true);
        /**
         * Set URL component is used to generate all kind of urls in the application
         */
        $di->set('url', function () use ($config) {
            $url = new UrlResolver();
            $url->setBaseUri($config->application->baseUri);
            $url->setStaticBaseUri($config->application->assetsUrl);
            return $url;
        }, true);
        $di->set('memCache', function () {
            $frontCache = new FrontendData([
                'lifetime' => 86400,
            ]);
            if(extension_loaded('memcached')) {
                $cache = new PhalconMemcached($frontCache, [
                    'servers' => [
                        [
                            'host'   => '127.0.0.1',
                            'port'   => 11211,
                            'weight' => 1
                        ]
                    ],
                    'client'  => [
                        \Memcached::OPT_HASH       => \Memcached::HASH_MD5,
                        \Memcached::OPT_PREFIX_KEY => 'prefix.',
                    ]
                ]);
            } else {
                $cache = new PhalconMemcache($frontCache, [
                    'host'       => 'localhost',
                    'port'       => 11211,
                    'persistent' => false
                ]);
            }
            return $cache;
        }, true);
        $di->set('cookies', function () {
            $cookies = new Cookies();
            if(defined('ENVIRONMENT') && ENVIRONMENT == 'development') {
                $cookies->useEncryption(true);
            } else {
                $cookies->useEncryption(true);
            }
            return $cookies;
        }, true);
        $di->set('crypt', function () {
            $crypt = new Crypt();
            $crypt->setKey('#joypaw.com@mzc#');
            return $crypt;
        }, true);
        //Registering the Models Manager
        $di->set('modelsManager', function () {
            return new ModelsManager();
        }, true);
        $di->set('modelsMetadata', function () {
            return new MetaDataMemory();
        }, true);

        $this->setDI($di);
    }

    public function start() {
        $this->registerAutoloaders();
        $this->registerServices();
        echo $this->handle()->getContent();
    }
}